﻿
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;

namespace AutoCreateCodePlus
{
    public class WriteIn
    {
        public bool CreateModel(string[] tableNames, string path, string contectString, string nameSpace)
        {
            bool isCreate = false;
            try
            {
                if (!Directory.Exists(path))//判断路径下是否存在该文件
                {
                    //根据目录创建指定的文件夹
                    Directory.CreateDirectory(path);
                }

                foreach (string name in tableNames)
                {
                    if (!String.IsNullOrEmpty(name))
                    {
                        //string logpath = string.Format(@"" + path + "\\{0}.cs", name);
                        string logpath = string.Format(@"" + path + "/{0}.cs", name);
                        if (File.Exists(logpath))
                        {
                            File.Delete(logpath);
                        }
                        DataTable dt = GetDataTable(name, contectString);
                        string str = CreateFile(dt, name, nameSpace);
                        File.AppendAllText(logpath, str);
                    }

                }
                isCreate = true;
            }
            catch (Exception)
            {
                isCreate = false;
            }
            return isCreate;

        }

        /// <summary>
        /// 创建服务
        /// </summary>
        /// <param name="className"></param>
        /// <param name="nameSpace"></param>
        /// <returns></returns>
        public string CreateServiceFile(string objecName, string className, string nameSpace)
        {
            StringBuilder srtBuilder = new StringBuilder();
            srtBuilder.AppendLine("//------------------------------------------------------------------------------");
            srtBuilder.AppendLine("//此代码由工具生成");
            srtBuilder.AppendLine("//请使用partial类进行扩展,避免修改被覆盖");
            srtBuilder.AppendLine("//createTime:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

            srtBuilder.AppendLine("//------------------------------------------------------------------------------");

            srtBuilder.AppendLine("using System.Linq.Expressions;");
            srtBuilder.AppendLine("using System;");
            srtBuilder.AppendLine("using System.Collections.Generic;");
            srtBuilder.AppendLine("using System.Linq;");
            srtBuilder.AppendLine("using XKPlatform.DataModels.Dao.BaseDao;");
            srtBuilder.AppendLine("using XKPlatform.DataModels.Dao.BaseEntity;");

            srtBuilder.AppendLine("using XKPlatform.DataModels;");
            srtBuilder.AppendLine("using XKPlatform.IService;");
            srtBuilder.AppendLine("using FreeSql;");

            srtBuilder.AppendLine("namespace XKPlatform.Service"); //BaseFreeSqlDao<OnlineUserInfo>, IOnlieUserinfoService
            srtBuilder.AppendLine("{");
            srtBuilder.AppendLine(string.Format("    public partial class {0}Service :BaseFreeSqlDao<{0}>, I{0}Service", objecName));
            srtBuilder.AppendLine("    {");
            srtBuilder.AppendLine(string.Format("            public bool AddModel({0} model)", objecName));
            srtBuilder.AppendLine("            {");
            srtBuilder.AppendLine("                return InsertAffrows(model) > 0;");
            srtBuilder.AppendLine("            }");
            srtBuilder.AppendLine("");
            srtBuilder.AppendLine(string.Format("            public bool BatchSave(List<{0}> models)", objecName));
            srtBuilder.AppendLine("            {");
            srtBuilder.AppendLine("                return BatchInsert(models) > 0;");
            srtBuilder.AppendLine("            }");
            srtBuilder.AppendLine("");
            srtBuilder.AppendLine(string.Format("            public (List<{0}> list, long count) GetList(Expression<Func<{0}, bool>> where, List<SortInfo<{0}, object>> orderbys = null, PageInfo pageInfo = null)", objecName));
            srtBuilder.AppendLine("            {");
            srtBuilder.AppendLine("                return Query(where, orderbys, pageInfo);");
            srtBuilder.AppendLine("            }");
            srtBuilder.AppendLine("");
            srtBuilder.AppendLine(string.Format("            public (List<{0}> list, long count) GetListByTbName(Expression<Func<{0}, bool>> where,string tbName, List<SortInfo<{0}, object>> orderbys = null, PageInfo pageInfo = null)", objecName));
            srtBuilder.AppendLine("            {");
            srtBuilder.AppendLine("                return Query(where, tbName,orderbys, pageInfo);");
            srtBuilder.AppendLine("            }");
            srtBuilder.AppendLine("");
            srtBuilder.AppendLine(string.Format("            public {0} GetModel(Expression<Func<{0}, bool>> where)", objecName));
            srtBuilder.AppendLine("            {");
            srtBuilder.AppendLine("                return GetByOne(where);");
            srtBuilder.AppendLine("            }");
            srtBuilder.AppendLine("");
            srtBuilder.AppendLine(string.Format("            public bool UpdateModel({0} model, Expression<Func<{0}, bool>> where, Expression<Func<{0}, object>> IgnoreLmbad = null)", objecName));
            srtBuilder.AppendLine("            {");
            srtBuilder.AppendLine("                return Update(model, where, IgnoreLmbad);");
            srtBuilder.AppendLine("            }");

            srtBuilder.AppendLine(string.Format("            public IUpdate<{0}> UpdateBySets(Expression<Func<{0}, bool>> where)", objecName));
            srtBuilder.AppendLine("            {");
            srtBuilder.AppendLine("                return this.UpdateBySet(where);");
            srtBuilder.AppendLine("            }");


            srtBuilder.AppendLine("    }");
            srtBuilder.AppendLine("}");
            return srtBuilder.ToString();

        }

        /// <summary>
        /// 创建服务接口
        /// </summary>
        /// <param name="className"></param>
        /// <param name="nameSpace"></param>
        /// <returns></returns>
        public string CreateIServiceFile(string objecName, string modelName, string className, string nameSpace)
        {
            StringBuilder srtBuilder = new StringBuilder();
            srtBuilder.AppendLine("//------------------------------------------------------------------------------");
            srtBuilder.AppendLine("//此代码由工具生成");
            srtBuilder.AppendLine("//请使用partial类进行扩展,避免修改被覆盖");
            srtBuilder.AppendLine("//createTime:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            srtBuilder.AppendLine("//------------------------------------------------------------------------------");

            srtBuilder.AppendLine("using System.Linq.Expressions;");
            srtBuilder.AppendLine("using System;");
            srtBuilder.AppendLine("using System.Collections.Generic;");
            srtBuilder.AppendLine("using System.Linq;");
            srtBuilder.AppendLine("using XKPlatform.DataModels;");
            srtBuilder.AppendLine("using XKPlatform.IService.IBaseService;");
            srtBuilder.AppendLine("namespace XKPlatform.IService");
            srtBuilder.AppendLine("{");
            srtBuilder.AppendLine(string.Format("    public partial interface I{0}Service: IFreeBaseService<{0}>, IScopeInject", objecName));
            srtBuilder.AppendLine("    {");

            srtBuilder.AppendLine("    }");

            srtBuilder.AppendLine("}");



            return srtBuilder.ToString();

        }

        public string Create(string[] tableNames, string[] objecNames, int tp, string path, string contectString, string nameSpace)
        {
            bool isCreate = false;
            string clsName = "";
            string retPath = "";
            try
            {
                if (!Directory.Exists(path))//判断路径下是否存在该文件
                {
                    //根据目录创建指定的文件夹
                    Directory.CreateDirectory(path);
                }
                int index = 0;
                foreach (string name in objecNames)
                {
                    var tableName = tableNames[index];
                    var objName = objecNames[index];
                    index++;
                    if (!String.IsNullOrEmpty(name))
                    {
                        var className = name;
                        if (tp == 1)
                        {
                            className = string.Format("{0}", objName);
                        }
                        //else if (tp == 2)
                        //{
                        //    className = string.Format("{0}Dao", name);
                        //}
                        else if (tp == 4)//创建服务
                        {
                            className = string.Format("{0}Service", name);
                        }
                        else if (tp == 5)//创建接口服务
                        {
                            className = string.Format("I{0}Service", name);

                        }

                        clsName = string.Format(@"{0}.cs", className);

                        var logpath = Path.Combine(path, clsName);
                        retPath += "\n" + logpath;

                        //// for mac 使用
                        //var logpath = "";
                        //logpath += "\n" + string.Format(@"" + path + "/{0}.cs", className);
                        if (File.Exists(logpath))
                        {
                            File.Delete(logpath);
                        }
                        DataTable dt = new DataTable();
                        var str = "";
                        if (tp == 1)//model
                        {
                            dt = GetDataTable(tableName, contectString);

                            var pkCol = getPKColByTable(tableName, contectString);

                            str = CreateModelFile(dt, tableName, className, nameSpace, pkCol);
                        }
                        //else if (tp == 2) //dao
                        //{
                        //    dt = GetDataTable(tableName, contectString);
                        //    str = CreateDaoFile(dt, className, nameSpace, tableName, name + "Model");
                        //}

                        else if (tp == 4)//服务
                        {
                            str = CreateServiceFile(name, className, nameSpace);
                        }
                        else if (tp == 5)//服务接口
                        {
                            str = CreateIServiceFile(name, objName, className, nameSpace);
                        }
                        File.AppendAllText(logpath, str);
                    }

                }
                isCreate = true;

            }
            catch (Exception ex)
            {
                retPath += "\n" + ex.Message.ToString();
                isCreate = false;
            }
            return clsName;// retPath;

        }

        /// <summary>
        /// 获取数据表中主键
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="connStr"></param>
        /// <returns></returns>
        private string getPKColByTable(string tableName, string connStr)
        {
            string str = string.Format(@"SELECT idx.name,   cols.name  as colname
FROM sys.index_columns idxcols
INNER JOIN sys.indexes idx ON idx.object_id = idxcols.object_id AND idx.index_id = idxcols.index_id
INNER JOIN sys.columns cols ON idx.object_id = cols.object_id AND idxcols.column_id = cols.column_id 
WHERE idxcols.object_id = object_id('{0}') and idx.name like 'PK%' 
ORDER BY idx.index_id", tableName);
            DataTable dt = ConntectData.Instance.GetTable(connStr, str);
            if (dt.Rows.Count > 0)
            {
                try
                {
                    return dt.Rows[0]["colname"].ToString();
                }
                catch
                {
                    return null;
                }
            }
            return "";
        }
        private string CreateModelFile(DataTable dt, string tableName, string fileName, string nameSpace, string pkName)
        {
            StringBuilder srtBuilder = new StringBuilder();
            srtBuilder.AppendLine("//------------------------------------------------------------------------------");
            srtBuilder.AppendLine("//此代码由工具生成");
            srtBuilder.AppendLine("//请使用partial类进行扩展,避免修改被覆盖");
            srtBuilder.AppendLine("//createTime:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

            srtBuilder.AppendLine("//------------------------------------------------------------------------------");
            srtBuilder.AppendLine("using System;");
            srtBuilder.AppendLine("using System.ComponentModel.DataAnnotations;");
            srtBuilder.AppendLine("using System.Text;");
            srtBuilder.AppendLine("using FreeSql.DataAnnotations;");
            srtBuilder.AppendLine("using XKPlatform.DataModels.Dao.BaseDao;");

            srtBuilder.AppendLine(string.Format("namespace {0}", nameSpace));
            srtBuilder.AppendLine("{");
            srtBuilder.AppendLine(string.Format(" [Table(DisableSyncStructure = true, Name = \"{0}\")]", tableName));
            srtBuilder.AppendLine(string.Format("    public partial class {0}: BaseEntity", fileName));
            srtBuilder.AppendLine("    {");
            srtBuilder.AppendLine("        ");

            var keyCol = "";//主键


            foreach (DataRow dr in dt.Rows)
            {
                if (dr["cname"].ToString() == pkName)
                {
                    srtBuilder.Append($"        [Column(IsPrimary = true)] \n");
                }
                if (!string.IsNullOrEmpty(dr["colDes"].ToString()) && dr["colDes"].ToString() != null)
                {
                    srtBuilder.Append($"        [Display(Name = \"{ dr["colDes"].ToString()}\")] \n");
                }
                srtBuilder.Append(string.Format("        public  {0}  {1} ", DataTypeToCType(dr["dtype"].ToString()), dr["cname"].ToString()));
                srtBuilder.AppendLine("{get;set;}");
            }
            srtBuilder.AppendLine("     }");
            srtBuilder.AppendLine("}");
            return srtBuilder.ToString();
        }

        /// <summary>
        /// 获取表结构，列名和数据类型
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="dataContectString"></param>
        /// <returns></returns>
        private DataTable GetDataTable(string tableName, string dataContectString)
        {
            string strSql = $"select c.name as cname ,p.name as dtype,stcc.colDes from sys.columns c,sys.objects t,sys.types p,SysTableColCfg stcc where t.name='{tableName}' and t.is_ms_shipped=0 and c.[object_id]=t.[object_id] and p.user_type_id=c.user_type_id and stcc.tbName ='{tableName}' and c.name = stcc.colName ";
            DataTable dt = ConntectData.Instance.GetTable(dataContectString, strSql);
            return dt;
        }

        /// <summary>
        /// 查询主键
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="dataContectString"></param>
        /// <returns></returns>
        private DataTable GetPriKeyCol(string tableName, string dataContectString)
        {

            string strSql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.columns WHERE TABLE_NAME='" + tableName + "' AND  COLUMNPROPERTY(OBJECT_ID('" + tableName + "'),COLUMN_NAME,'IsIdentity')=1";
            DataTable dt = ConntectData.Instance.GetTable(dataContectString, strSql);
            return dt;
        }
        /// <summary>
        /// 查询自增列
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="dataContectString"></param>
        /// <returns></returns>
        private DataTable GetIdentiCol(string tableName, string dataContectString)
        {
            //查询自增
            var strSql = "SELECT SYSCOLUMNS.name FROM SYSCOLUMNS,SYSOBJECTS,SYSINDEXES,SYSINDEXKEYS WHERE SYSCOLUMNS.id = object_id('" + tableName + "') AND SYSOBJECTS.xtype = 'PK' AND SYSOBJECTS.parent_obj = SYSCOLUMNS.id AND SYSINDEXES.id = SYSCOLUMNS.id AND SYSOBJECTS.name = SYSINDEXES.name AND SYSINDEXKEYS.id = SYSCOLUMNS.id AND SYSINDEXKEYS.indid = SYSINDEXES.indid AND SYSCOLUMNS.colid = SYSINDEXKEYS.colid";

            DataTable dt = ConntectData.Instance.GetTable(dataContectString, strSql);
            return dt;
        }

        private string CreateFile(DataTable dt, string fileName, string nameSpace)
        {
            StringBuilder srtBuilder = new StringBuilder();
            srtBuilder.AppendLine("/*-------------");
            srtBuilder.AppendLine("------------*/");
            srtBuilder.AppendLine("using System;");
            srtBuilder.AppendLine("using System.Text;");
            srtBuilder.AppendLine(string.Format("namespace {0}", nameSpace));
            srtBuilder.AppendLine("{");
            srtBuilder.AppendLine(string.Format("    public class {0}", fileName));
            srtBuilder.AppendLine("    {");
            srtBuilder.AppendLine("        #region 私有变量");
            srtBuilder.AppendLine("        ");
            foreach (DataRow dr in dt.Rows)
            {
                srtBuilder.AppendLine(string.Format("        private  {0}  {1} ;", DataTypeToCType(dr["dtype"].ToString()), "_" + dr["cname"].ToString().ToLower()));
            }
            srtBuilder.AppendLine("        #endregion");
            srtBuilder.AppendLine("        ");
            srtBuilder.AppendLine("        #region 公共属性变量");
            srtBuilder.AppendLine("        ");
            foreach (DataRow dr in dt.Rows)
            {
                srtBuilder.AppendLine(string.Format("        public  {0}  {1} ", DataTypeToCType(dr["dtype"].ToString()),
                    dr["cname"].ToString()));
                srtBuilder.AppendLine("        {");
                // srtBuilder.AppendLine(string.Format("get { return {0};}", "_" + dr["cname"].ToString().ToLower()));
                srtBuilder.AppendLine("           get");
                srtBuilder.AppendLine("            {");
                srtBuilder.AppendLine(string.Format("                return {0};", "_" + dr["cname"].ToString().ToLower()));
                srtBuilder.AppendLine("            }");
                srtBuilder.AppendLine("           set ");
                srtBuilder.AppendLine("            {");
                srtBuilder.AppendLine(string.Format("                {0}=value;", "_" + dr["cname"].ToString().ToLower()));
                srtBuilder.AppendLine("            }");
                srtBuilder.AppendLine("        }");
                // srtBuilder.AppendLine(string.Format("set{{0} =value;}", "_" + dr["cname"].ToString().ToLower()));
                srtBuilder.AppendLine("        ");
            }
            srtBuilder.AppendLine("        #endregion");
            srtBuilder.AppendLine("        ");
            srtBuilder.AppendLine("    }");
            srtBuilder.AppendLine("}");
            return srtBuilder.ToString();
        }

        /// <summary>
        /// c#中数据类型与sqlserver数据类型对应关系
        /// </summary>
        /// <param name="dataType">数据类型</param>
        /// <returns></returns>
        private static string DataTypeToCType(string dataType)
        {
            var retType = string.Empty;
            if (dataType.Equals("text") || dataType.Equals("varchar") || dataType.Equals("char") || dataType.Equals("nvarchar") || dataType.Equals("nchar") || dataType.Equals("ntext") || dataType.Equals("uniqueidentifier"))
                return "string";
            if (dataType.Equals("int"))
                return "int";
            if (dataType.Equals("smallint"))
                return "Int16";
            if (dataType.Equals("tinyint"))
                return "byte";
            if (dataType.Equals("bigint"))
                return "long";
            if (dataType.Equals("bit"))
                return "bool";
            if (dataType.Equals("money") || dataType.Equals("smallmoney") || dataType.Equals("numeric") || dataType.Equals("decimal"))
                return "decimal";
            if (dataType.Equals("datetime") || dataType.Equals("smalldatetime") || dataType.Equals("timestamp") || dataType.Equals("datetime2"))
                return "DateTime?";
            if (dataType.Equals("real"))
                return "Single";
            if (dataType.Equals("float"))
                return "double";
            if (dataType.Equals("image") || dataType.Equals("binary") || dataType.Equals("varbinary"))
                return "byte[]";
            return dataType.Equals("uniqueidentifier") ? "Guid" : retType;
        }

        private static string DataTypeToConvertString(string dataType, string value)
        {
            var retType = string.Empty;


            if (dataType.Equals("text") || dataType.Equals("varchar") || dataType.Equals("char") || dataType.Equals("nvarchar") || dataType.Equals("nchar") || dataType.Equals("ntext") || dataType.Equals("uniqueidentifier"))
                return string.Format("{0}.ToString()", value);
            if (dataType.Equals("int"))
                return string.Format("{0}.ObjectToInt(0)", value);
            if (dataType.Equals("smallint"))
                return string.Format("{0}.ObjectToShort(0)", value);
            if (dataType.Equals("tinyint"))
                return string.Format("{0}.ObjectToByte(0)", value);
            if (dataType.Equals("bigint"))
                return string.Format("{0}.ObjectToInt64(0)", value);
            if (dataType.Equals("bit"))
                return string.Format("{0}.ObjectToBoolean(false)", value);
            if (dataType.Equals("money") || dataType.Equals("smallmoney") || dataType.Equals("numeric") || dataType.Equals("decimal"))
                return string.Format("{0}.ObjectToDecimal(0.0m)", value);
            if (dataType.Equals("datetime") || dataType.Equals("smalldatetime") || dataType.Equals("timestamp") || dataType.Equals("datetime2"))
                return string.Format("{0}.ObjectToDateTime()", value);
            if (dataType.Equals("float"))
                return string.Format("{0}.ToString().ToDouble()", value);


            throw new Exception("未知的数据类型");
        }





    }
}
